﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DataAccess = Microsoft.MSE.Catalog.Module.Data;
using DTO = Microsoft.MSE.Catalog.Contracts;
using WSDL = System.Web.Services.Description;
using System.Xml;
using System.Data.SqlClient;
using System.Xml.Schema;
using System.Collections;
using System.IO;
using System.Data;

namespace Microsoft.MSE.Catalog.Module.Business
{
    public class SchemaManager
    {
        public SchemaManager()
        {

        }

        #region Schema functions

        public static Guid CreateSchema(DTO.Schema schema)
        {
            using (SqlConnection conn = CatalogSvcHelper.GetConnection())
            {
                conn.Open();
                SqlTransaction txn = CatalogSvcHelper.GetTransaction(conn, IsolationLevel.Serializable);

                Guid schID = DataAccess.Entity.GetIDFromName(schema.Name, Microsoft.MSE.Catalog.Contracts.EntityClass.Schema, txn, conn);
                if (schID == Guid.Empty)
                {
                    try
                    {
                        DataAccess.Schema.CreateSchemaNamespace(schema, txn, conn);

                        if ((schema.Objects != null && schema.Objects.Count > 0) ||
                            (schema.XSD != null && schema.XSD.OuterXml.Length > 0))
                        {
                            CreateSchemaObjects(schema, txn, conn);
                        }
                        if (schema.ImportedSchemas != null && schema.ImportedSchemas.Count > 0)
                        {
                            foreach (DTO.SchemaImport import in schema.ImportedSchemas)
                            {
                                DataAccess.SchemaImport.CreateSchemaImport(schema.ID, import, txn, conn);
                            }
                        }

                        if (txn != null) txn.Commit();

                        return schema.ID;
                    }
                    catch (Exception)
                    {
                        if (txn != null) txn.Rollback();
                        throw;
                    }
                }
                else
                {
                    if (txn != null) txn.Rollback(); //Rollback transaction
                    throw new ApplicationException("This Schema namepace already exists in the Service Model");
                }
            }
        }
        public static DTO.SchemaObject CreateOrUpdateSchemaObject(DTO.SchemaObject schemaObject, SqlTransaction txn, SqlConnection conn)
        {
            DTO.SchemaObject currentSchemaObject = null;

            if (string.IsNullOrEmpty(schemaObject.NamespaceUri) == false)
            {
                // Get the schema
                Guid schemaID = Data.Entity.GetIDFromName(schemaObject.NamespaceUri, DTO.EntityClass.Schema, txn, conn);

                // Check if SchemaObject already Exists
                currentSchemaObject = Data.SchemaObject.GetSchemaObject(schemaObject.ID, txn, conn);

                if (currentSchemaObject != null && currentSchemaObject.ID != Guid.Empty)
                {
                    // Existing SchemaObject
                    if (CheckIfSchemaObjectsEqual(schemaObject, currentSchemaObject) == false)
                    {
                        DTO.Schema schema = GetSchema(schemaID, null, null);
                        currentSchemaObject = schema.Objects.First(x => x.ID == schemaObject.ID);
                        currentSchemaObject.Xml = schemaObject.Xml;
                        UpdateSchema(schema, txn, conn);
                    }
                }
                else
                {
                    DTO.Schema schema = GetSchema(schemaID, null, null);
                    schema.Objects.Add(schemaObject);
                    UpdateSchema(schema, txn, conn);
                    currentSchemaObject = schema.Objects.First(x => x.Name == schemaObject.Name);
                }
            }
            else
            {
                throw new ApplicationException(string.Format("Invalid SchemaObject with Name=[{0}] is missing the Namespace member", schemaObject.Name));
            }
            return currentSchemaObject;
        }
        public static void UpdateSchemaObjectReferences(List<Guid> oldSchemaObjectIDs, Guid newSchemaObjectID, bool removeOldVersion, SqlTransaction txn, SqlConnection conn)
        {
            bool closeConnection = false;
            bool completeTransaction = false;

            try
            {
                if ((oldSchemaObjectIDs != null && oldSchemaObjectIDs.Count > 0) &&
                    newSchemaObjectID != Guid.Empty)
                {
                    foreach (Guid oldSchemaObjectID in oldSchemaObjectIDs)
                    {
                        DTO.SchemaObject oldSchemaObject = GetSchemaObjectByID(oldSchemaObjectID, false);
                        DTO.SchemaObject newSchemaObject = GetSchemaObjectByID(newSchemaObjectID, false);
                        List<DTO.Entity> references = ListSchemaObjectReferences(oldSchemaObjectID, txn, conn);

                        if (references != null && references.Count > 0)
                        {
                            foreach (DTO.Entity entity in references)
                            {
                                switch (entity.EntityClass)
                                {
                                    case DTO.EntityClass.OperationVersion:
                                        OperationManager.UpdateOperationVersionSchemaObjectReferences(entity.ID, oldSchemaObject, newSchemaObject, txn, conn);
                                        break;

                                    case DTO.EntityClass.Resource:
                                        OperationManager.UpdateResourceSchemaObjectReferences(entity.ID, oldSchemaObject, newSchemaObject, txn, conn);
                                        break;

                                    case DTO.EntityClass.AssertionType:
                                        PolicyManager.UpdateAssertionTypeSchemaObjectReferences(entity.ID, oldSchemaObject, newSchemaObject, txn, conn);
                                        break;

                                    case DTO.EntityClass.SchemaObject:
                                        DataAccess.SchemaObject.UpdateSchemaObjectReferences(oldSchemaObject.ID, newSchemaObject.ID, txn, conn);
                                        break;
                                }
                            }
                        }
                    }
                }
                if (removeOldVersion)
                {
                    DTO.SchemaObject oldSchemaObject = GetSchemaObjectByID(oldSchemaObjectIDs[0], false);
                    DTO.DataEntity dataEntity = null;

                    if (oldSchemaObject.Type == DTO.SchemaObjectType.Element)
                    {
                        dataEntity = DataEntityManager.GetDataEntity(oldSchemaObject.DataEntityID);
                    }
                    foreach (Guid oldSchemaObjectID in oldSchemaObjectIDs)
                    {
                        // Delete that from the database
                        DataAccess.SchemaObject.DeleteSchemaObject(oldSchemaObjectID,txn,conn);
                        if (oldSchemaObject.Type == DTO.SchemaObjectType.Element)
                        {
                            // Remove the data entity if there are no schema objects associated
                            dataEntity.SchemaObjects.RemoveAll(x => x.ID == oldSchemaObjectID);
                            if (dataEntity.SchemaObjects.Count == 0)
                            {
                                DataEntityManager.DeleteDataEntity(dataEntity.ID);
                            }
                        }
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
        }
        
        public static DTO.Schema UpdateSchema(DTO.Schema schema,SqlTransaction txn, SqlConnection conn)
        {
            bool closeConnection = false;
            bool completeTransaction = false;

            if (conn == null)
            {
                closeConnection = true;
                conn = CatalogSvcHelper.GetConnection();
                conn.Open();
            }
            if (txn == null)
            {
                completeTransaction = true;
                txn = CatalogSvcHelper.GetTransaction(conn, IsolationLevel.Serializable);
            }
            Guid schID = DataAccess.Entity.GetIDFromName(schema.Name, Microsoft.MSE.Catalog.Contracts.EntityClass.Schema, txn, conn);
            if (schID == Guid.Empty || (schID.CompareTo(schema.ID) == 0))
            {
                try
                {

                    DataAccess.Schema.UpdateSchema(schema, txn, conn);

                    // Update Schema Objects
                    if ((schema.Objects != null && schema.Objects.Count > 0) ||
                        (schema.XSD != null && schema.XSD.OuterXml.Length > 0))
                    {
                        CreateSchemaObjects(schema, txn, conn);
                    }
                    // Update Schema Imports
                    if (schema.ImportedSchemas != null && schema.ImportedSchemas.Count > 0)
                    {
                        DataAccess.SchemaImport.DeleteSchemaImport(schema.ID, txn, conn);
                        foreach (DTO.SchemaImport schemaImport in schema.ImportedSchemas)
                        {
                            DataAccess.SchemaImport.CreateSchemaImport(schema.ID, schemaImport, txn, conn);
                        }
                    }

                    if (completeTransaction == true)
                    {
                        if (txn != null) txn.Commit();
                    }
                    if (closeConnection == true)
                    {
                        if (conn != null) conn.Close();
                    }
                }
                catch (Exception)
                {
                    if (completeTransaction == true)
                    {
                        if (txn != null) txn.Rollback();
                    }
                    if (closeConnection == true)
                    {
                        if (conn != null) conn.Close();
                    }
                    throw;
                }
            }
            else
            {
                if (txn != null) txn.Rollback(); //Rollback transaction
                throw new ApplicationException("This Schema namepace already exists under a differnt entry in the Service Model");
            }

            return schema;
        }
        public static void ValidateSchema(DTO.Schema schema, SqlTransaction txn, SqlConnection conn)
        {
            try
            {
                Dictionary<string, Guid> mappedElemntHash = new Dictionary<string, Guid>();
                Dictionary<string, Guid> schemaHash = new Dictionary<string, Guid>();
                List<Guid> schemaIDs = new List<Guid>();
                XmlSchemaSet xssImport = new XmlSchemaSet();

                XmlSchema xs = null;
                if (schema.Objects != null && schema.Objects.Count > 0)
                    xs = CatalogSvcHelper.CreateXmlSchemaFromSchema(schema, false);
                else
                    xs = CatalogSvcHelper.LoadXmlSchemaFromString(schema.XSD.OuterXml);
                xssImport.Add(xs);
                CollectRealatedSchemas(schema, schemaHash, schemaIDs, xssImport, txn, conn);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(string.Format("An error occurred while validating Schema [{0}]", schema.NamespaceURI), ex);
            }

        }
        public static List<Guid> ImportSchemas(List<DTO.Schema> importedSchemas)
        {
            Dictionary<string, Guid> schemaHash = new Dictionary<string, Guid>();
            Dictionary<string, Guid> mappedElemntHash = new Dictionary<string, Guid>();
            List<Guid> schemaIDs = new List<Guid>();
            XmlSchemaSet xssImport = new XmlSchemaSet();

            using (SqlConnection conn = CatalogSvcHelper.GetConnection())
            {
                conn.Open();
                SqlTransaction txn = CatalogSvcHelper.GetTransaction(conn, IsolationLevel.Serializable);

                try
                {
                    foreach (DTO.Schema schema in importedSchemas)
                    {
                        XmlSchema xs = CatalogSvcHelper.LoadXmlSchemaFromString(schema.XSD.OuterXml);

                        Guid schemaID = DataAccess.Entity.GetIDFromName(schema.NamespaceURI, DTO.EntityClass.Schema, txn,conn);
                        if (schemaID == null || schemaID == Guid.Empty)
                        {
                            schemaID = DataAccess.Schema.CreateSchemaNamespace(schema, txn, conn);
                        }
                        else
                        {
                            schema.ID = schemaID;
                            DataAccess.SchemaImport.DeleteSchemaImport(schema.ID, txn, conn);
                        }
                        if (schema.ImportedSchemas != null && schema.ImportedSchemas.Count > 0)
                        {
                            foreach (DTO.SchemaImport schemaImport in schema.ImportedSchemas)
                            {
                                DataAccess.SchemaImport.CreateSchemaImport(schema.ID, schemaImport, txn, conn);
                            }
                        }
                        schemaIDs.Add(schemaID);
                        schemaHash.Add(schema.NamespaceURI, schemaID);
                        xssImport.Add(xs);
                    }
                    xssImport.Compile();

                    foreach (XmlSchema xs in xssImport.Schemas())
                    {
                        CreateSchemaObjectsFromXmlSchema(xssImport, xs, mappedElemntHash, schemaHash, txn, conn);
                    }

                    if (txn != null) txn.Commit();
                    
                    return schemaIDs;
                }
                catch (Exception ex)
                {
                    if (txn != null) txn.Rollback();
                    throw new ApplicationException(string.Format("An error occurred while saving Schema and Objects for Import [{0}]",CatalogSvcHelper.GetExceptionDetails(ex)));
                }
            }
        }


        public static void DeleteSchema(Guid ID)
        {
            using (SqlConnection conn = CatalogSvcHelper.GetConnection())
            {
                conn.Open();
                SqlTransaction txn = CatalogSvcHelper.GetTransaction(conn, IsolationLevel.Serializable);

                try
                {
                    // Check for any Schemas referencing this one
                    DTO.SchemaList schemaList = DataAccess.Schema.ListReferencedBySchemas(ID, txn, conn);
                    if (schemaList.Schemas != null && schemaList.Schemas.Count > 0)
                    {
                        bool referencedBy = false;
                        foreach (DTO.SchemaListElement sle in schemaList.Schemas)
                        {
                            if (sle.ID != ID)
                            {
                                referencedBy = true;
                                break;
                            }
                        }
                        if (referencedBy == true)
                        {
                            throw new ApplicationException(string.Format("This schema [{0}] cannot be deleted as it is referenced by one or more schemas in the catalog", ID));
                        }
                    }
                    DataAccess.Schema.DeleteSchema(ID, txn, conn);

                    if (txn != null) txn.Commit();
                }
                catch (Exception)
                {
                    if (txn != null) txn.Rollback();
                    throw;
                }
            }
        }

        public static DTO.Schema GetSchema(Guid ID, SqlTransaction txn, SqlConnection conn)
        {

            DTO.Schema schema = new DTO.Schema();
            XmlSchema xmlSchema = null;

            schema = DataAccess.Schema.GetSchema(ID, txn, conn);

            xmlSchema = new XmlSchema();
            xmlSchema.TargetNamespace = schema.NamespaceURI;
            xmlSchema.AttributeFormDefault = schema.AttributeFormDefault;
            xmlSchema.ElementFormDefault = schema.ElementFormDefault;

            // Append Imports
            xmlSchema = DataAccess.Schema.AppendImportsToSchema(schema, xmlSchema, txn, conn);
            // Append Objects
            xmlSchema = DataAccess.Schema.AppendObjectsToSchema(schema, xmlSchema, txn, conn);

            XmlDocument schemaDoc = CatalogSvcHelper.ConverXmlSchemaToDOM(xmlSchema);
            schema.XSD = schemaDoc.DocumentElement;

            return schema;
        }
        /// <summary>
        /// Returns the equivalent Schema Object in terms of 
        /// Name
        /// NamespaceUri
        /// Type
        /// Contents
        /// </summary>
        /// <remarks>This function is normally called from teh Archiver Tool</remarks>
        /// <param name="schemaObject"></param>
        /// <returns></returns>
        public static DTO.SchemaObject GetEquivalentSchemaObject(DTO.SchemaObject schemaObject, ref bool hasItems, SqlTransaction txn, SqlConnection conn)
        {
            DTO.SchemaObject equivalentSchemaObject = null;
            hasItems = false;

            List<DTO.SchemaObject> existingSchemaObjects = DataAccess.SchemaObject.ListSchemaObjectByNameTypeAndNamespace(schemaObject.NamespaceUri, schemaObject.Name, schemaObject.Type, txn,conn);

            if (existingSchemaObjects != null && existingSchemaObjects.Count > 0)
            {
                hasItems = true;
                // Now check if the schema object matches any existing version
                foreach (DTO.SchemaObject existingSchemaObject in existingSchemaObjects)
                {
                    if (CheckIfSchemaObjectsEqual(schemaObject, existingSchemaObject) == true)
                    {
                        equivalentSchemaObject = existingSchemaObject;
                        break;
                    }
                }
            }
            return equivalentSchemaObject;
        }


        public static DTO.SchemaObject GetSchemaObjectByNameTypeAndNamespace(string namespaceUri, string name, DTO.SchemaObjectType type)
        {
            return DataAccess.SchemaObject.GetSchemaObjectByNameTypeAndNamespace(namespaceUri, name, type,null,null);
        }

        public static List<DTO.SchemaObject> ListSchemaObjectByNameTypeAndNamespace(string namespaceUri, string name, DTO.SchemaObjectType type)
        {
            return DataAccess.SchemaObject.ListSchemaObjectByNameTypeAndNamespace(namespaceUri, name, type, null, null);
        }

        public static DTO.SchemaObject GetSchemaObjectByID(Guid schemaObjectID, bool loadDependencies)
        {
            return DataAccess.SchemaObject.GetSchemaObjectByID(schemaObjectID, loadDependencies, null, null);
        }

        public static Dictionary<string, XmlSchema> LoadAllSchemasForEndpoint(DTO.Endpoint endpoint, SqlTransaction txn, SqlConnection conn)
        {
            XmlSchemaSet xss = new XmlSchemaSet();
            Dictionary<string, XmlSchema> schemaHash = new Dictionary<string, XmlSchema>();

            List<DTO.Schema> schemaList = ListSchemasForEndpoint(endpoint.ID, txn, conn);
            if (schemaList != null && schemaList.Count > 0)
            {
                foreach (DTO.Schema schema in schemaList)
                {
                    if (schemaHash.ContainsKey(schema.NamespaceURI) == false)
                    {
                        XmlSchema xs = CatalogSvcHelper.LoadSchemaFromString(schema.XSD.OuterXml);
                        schemaHash.Add(xs.TargetNamespace, xs);
                    }
                }
            }
            return schemaHash;
        }

        public static List<DTO.Schema> ListSchemasForEndpoint(Guid ID, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.Schema.ListSchemasForEndpoint(ID, txn, conn);
        }

        public static List<DTO.SchemaObject> ListSchemaObjectDependencies(Guid ID, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.SchemaObject.ListSchemaObjectDependencies(ID, txn, conn);
        }

        public static List<DTO.Entity> ListSchemaObjectReferences(Guid ID, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.SchemaObject.ListSchemaObjectReferences(ID, txn, conn);
        }

        public static List<DTO.SchemaListElement> ListSchemasByGroup(Guid entityGroupID, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.Schema.ListSchemasByGroup(entityGroupID, txn, conn);
        }

        public static DTO.SchemaList ListSchemas(SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.Schema.ListSchemas(txn, conn);
        }

        public static DTO.Schema GetSchemaByNamespace(string namespaceUri, SqlTransaction txn, SqlConnection conn)
        {
            DTO.Schema schema = null;

            Guid ID = DataAccess.Entity.GetIDFromName(namespaceUri, DTO.EntityClass.Schema, txn, conn);
            if (CatalogSvcHelper.IsGuidNullOrEmpty(ID.ToString()) == false)
            {
                schema = GetSchema(ID, txn, conn);
            }
            else
            {
                throw new ApplicationException(string.Format("Schema ID is not found [{0}]", namespaceUri));
            }

            return schema;
        }

        public static WSDL.ServiceDescription CreateServiceDesciptionFromSchemas(Dictionary<string, XmlSchema> schemaHash, List<DTO.OperationVersion> operationVersions, string serviceNamespace)
        {

            WSDL.ServiceDescription serviceDescription = new System.Web.Services.Description.ServiceDescription();

            // Validate Schemas
            try
            {
                XmlSchemaSet xss = new XmlSchemaSet();
                foreach (XmlSchema xs in schemaHash.Values)
                {
                    xss.Add(xs);
                }
                xss.Compile();
            }
            catch (Exception ex)
            {
                throw new ApplicationException(string.Format("Failed to validate schemas as schema set compilation failed due to error [{0}]", CatalogSvcHelper.GetExceptionDetails(ex)));
            }

            foreach (XmlSchema xs in schemaHash.Values)
            {
                serviceDescription.Types.Schemas.Add(xs);
            }

            // We need to assign a targetnamespace to the WSDL
            // Assigning it using the object model i.e. serviceDescription.TargetNamespace cause the WSDL to loose all the namespaces 
            // that it has while we assigned types (schemas) to it
            string data = CatalogSvcHelper.ConvertWSDLToString(serviceDescription);

            XmlDocument xdoc = new XmlDocument();
            xdoc.LoadXml(data);
            XmlAttribute xat = xdoc.CreateAttribute("xmlns:tns");
            xat.Value = serviceNamespace;
            xdoc.DocumentElement.Attributes.Append(xat);

            xat = xdoc.CreateAttribute("targetNamespace");
            xat.Value = serviceNamespace;
            xdoc.DocumentElement.Attributes.Append(xat);

            serviceDescription = WSDL.ServiceDescription.Read(new StringReader(xdoc.OuterXml));
            return serviceDescription;
        }

        public static void LoadImportedSchemas(XmlSchemaSet schemaSet, Dictionary<string, string> schemaHash, XmlDocument schemaDoc, SqlTransaction txn, SqlConnection conn)
        {
            XmlNamespaceManager xmlns = new XmlNamespaceManager(schemaDoc.NameTable);
            xmlns.AddNamespace("xsd", XmlSchema.Namespace);
            XmlNodeList importNodes = schemaDoc.SelectNodes("//xsd:import", xmlns);
            foreach (XmlNode xn in importNodes)
            {
                string name = null;
                if (xn.Attributes["namespace"] != null) name = xn.Attributes["namespace"].Value;

                if (schemaHash.ContainsKey(name) == false)
                {
                    DTO.Schema schema = GetSchemaByNamespace(name, txn, conn);
                    XmlSchema xmlSchema = XmlSchema.Read(new StringReader(schema.XSD.OuterXml), null);
                    schemaSet.Add(xmlSchema);
                    schemaHash.Add(name, name);
                    XmlDocument importedSchemaDoc = new XmlDocument();
                    importedSchemaDoc.LoadXml(schema.XSD.OuterXml);

                    LoadImportedSchemas(schemaSet, schemaHash, importedSchemaDoc, txn, conn);
                }
            }

        }
        public static XmlSchemaSet ExtractSchemaSetFromRelevantSchemaTypes(List<DTO.MessagePart> messageParts, SqlTransaction txn, SqlConnection conn)
        {
            XmlSchemaSet xssRelevant = new XmlSchemaSet();
            Dictionary<string, XmlSchema> relevantSchemaHash = new Dictionary<string, XmlSchema>();
            Dictionary<Guid, string> mappedElemntHash = new Dictionary<Guid, string>();

            try
            {
                foreach (DTO.MessagePart messagePart in messageParts)
                {
                    DTO.SchemaObject schemaObject = messagePart.SchemaObject;
                    if (DataAccess.SchemaObject.AddTypeToSchemaAndHash(schemaObject, relevantSchemaHash, mappedElemntHash, txn, conn) == false)
                    {
                        DataAccess.SchemaObject.AppendDependencyObjectsToSchema(schemaObject, relevantSchemaHash, mappedElemntHash, txn, conn);
                    }
                }
                // Make sure that this schema set can be compiled
                foreach (XmlSchema xsRelevant in relevantSchemaHash.Values)
                {
                    xssRelevant.Add(xsRelevant);
                    //string schemaXml = SerializeSchema(xsRelevant);
                }
                xssRelevant.Compile();
            }
            catch (Exception ex)
            {
                throw new ApplicationException(string.Format("Failed to extrat relevant schema types due to error [{0}]", CatalogSvcHelper.GetExceptionDetails(ex)), ex);
            }
            return xssRelevant;
        }


        public static Dictionary<string, XmlSchema> ExtractRelevantSchemaTypes(List<DTO.OperationVersion> operationVersions, bool optimizeWsdl, SqlTransaction txn, SqlConnection conn)
        {
            Dictionary<string, XmlSchema> relevantSchemaHash = new Dictionary<string, XmlSchema>();
            Dictionary<Guid, string> mappedElemntHash = new Dictionary<Guid, string>();

            try
            {
                foreach (DTO.OperationVersion operationVersion in operationVersions)
                {
                    if (operationVersion.RequestMsg != null)
                    {
                        foreach (DTO.MessagePart messagePart in operationVersion.RequestMsg)
                        {
                            DTO.SchemaObject schemaObject = messagePart.SchemaObject;
                            if (DataAccess.SchemaObject.AddTypeToSchemaAndHash(schemaObject, relevantSchemaHash, mappedElemntHash, txn, conn) == false)
                            {
                                DataAccess.SchemaObject.AppendDependencyObjectsToSchema(schemaObject, relevantSchemaHash, mappedElemntHash, txn, conn);
                            }
                        }
                    }
                    if (operationVersion.ResponseMsg != null)
                    {
                        foreach (DTO.MessagePart messagePart in operationVersion.ResponseMsg)
                        {
                            DTO.SchemaObject schemaObject = messagePart.SchemaObject;
                            if (DataAccess.SchemaObject.AddTypeToSchemaAndHash(schemaObject, relevantSchemaHash, mappedElemntHash, txn, conn) == false)
                            {
                                DataAccess.SchemaObject.AppendDependencyObjectsToSchema(schemaObject, relevantSchemaHash, mappedElemntHash, txn, conn);
                            }
                        }
                    }
                    if (operationVersion.SoapFaults != null)
                    {
                        foreach (DTO.SoapFault soapFault in operationVersion.SoapFaults)
                        {
                            DTO.SchemaObject schemaObject = soapFault.SchemaObject;
                            if (DataAccess.SchemaObject.AddTypeToSchemaAndHash(schemaObject, relevantSchemaHash, mappedElemntHash, txn, conn) == false)
                            {
                                DataAccess.SchemaObject.AppendDependencyObjectsToSchema(schemaObject, relevantSchemaHash, mappedElemntHash, txn, conn);
                            }
                        }
                    }
                    if (operationVersion.RequestHeaders != null)
                    {
                        foreach (DTO.MessageHeader messageHeader in operationVersion.RequestHeaders)
                        {
                            DTO.SchemaObject schemaObject = messageHeader.SchemaObject;
                            if (DataAccess.SchemaObject.AddTypeToSchemaAndHash(schemaObject, relevantSchemaHash, mappedElemntHash, txn, conn) == false)
                            {
                                DataAccess.SchemaObject.AppendDependencyObjectsToSchema(schemaObject, relevantSchemaHash, mappedElemntHash, txn, conn);
                            }
                        }
                    }
                    if (operationVersion.ResponseHeaders != null)
                    {
                        foreach (DTO.MessageHeader messageHeader in operationVersion.ResponseHeaders)
                        {
                            DTO.SchemaObject schemaObject = messageHeader.SchemaObject;
                            if (DataAccess.SchemaObject.AddTypeToSchemaAndHash(schemaObject, relevantSchemaHash, mappedElemntHash, txn, conn) == false)
                            {
                                DataAccess.SchemaObject.AppendDependencyObjectsToSchema(schemaObject, relevantSchemaHash, mappedElemntHash, txn, conn);
                            }
                        }
                    }
                }
                // We need to return all the schema objects for the schema including both related and un-related
                if (optimizeWsdl == false)
                {
                    foreach (XmlSchema xs in relevantSchemaHash.Values)
                    {
                        List<DTO.SchemaObject> schemaObjects = DataAccess.SchemaObject.ListSchemaObjectForSchemaNamespace(xs.TargetNamespace, txn, conn);
                        foreach (DTO.SchemaObject schemaObject in schemaObjects)
                        {
                            if (DataAccess.SchemaObject.AddTypeToSchemaAndHash(schemaObject, relevantSchemaHash, mappedElemntHash, txn, conn) == false)
                            {
                                DataAccess.SchemaObject.AppendDependencyObjectsToSchema(schemaObject, relevantSchemaHash, mappedElemntHash, txn, conn);
                            }
                        }
                    }
                }
                // Make sure that this schema set can be compiled
                XmlSchemaSet xssRelevant = new XmlSchemaSet();
                foreach (XmlSchema xsRelevant in relevantSchemaHash.Values)
                {
                    xssRelevant.Add(xsRelevant);
                    string schemaXml = CatalogSvcHelper.SerializeSchema(xsRelevant);
                }
                xssRelevant.Compile();
            }
            catch (Exception ex)
            {
                throw new ApplicationException(string.Format("Failed to extrat relevant schema types due to error [{0}]", CatalogSvcHelper.GetExceptionDetails(ex)), ex);
            }
            return relevantSchemaHash;
        }

        #region Schema Private methods
        
        
        private static XmlSchema GetSchemaFromMap(Dictionary<string, XmlSchema> schemaHash, string schemaNamepsace)
        {
            XmlSchema xs = null;
            if (schemaHash.ContainsKey(schemaNamepsace) == false)
            {
                xs = new XmlSchema();
                xs.TargetNamespace = schemaNamepsace;
                xs.ElementFormDefault = XmlSchemaForm.Qualified;
                schemaHash.Add(schemaNamepsace, xs);
            }
            else
            {
                xs = schemaHash[schemaNamepsace];
            }
            return xs;
        }

        private static XmlElement SerializeSchemaObject(XmlSchemaObject xso, string schemaNamespace)
        {
            XmlSchema xmlSchema = new XmlSchema();
            xmlSchema.TargetNamespace = schemaNamespace;
            xmlSchema.ElementFormDefault = XmlSchemaForm.Qualified;
            xmlSchema.Items.Add(xso);

            StringBuilder sb = new StringBuilder();
            XmlWriter xw = XmlWriter.Create(sb);
            xmlSchema.Write(xw);
            xw.Flush();

            XmlDocument schemaDoc = new XmlDocument();
            schemaDoc.LoadXml(sb.ToString());
            return (XmlElement)schemaDoc.DocumentElement;
        }
        private static XmlSchemaAttributeGroup GetAttributeFromSchmea(XmlSchemaSet schemaSet, XmlQualifiedName qualifiedName)
        {
            ICollection schemas = schemaSet.Schemas();
            XmlSchemaAttributeGroup xsag = null;
            foreach (XmlSchema schema in schemas)
            {
                if (string.Compare(schema.TargetNamespace, qualifiedName.Namespace, true) == 0)
                {
                    xsag = (XmlSchemaAttributeGroup)schema.AttributeGroups[qualifiedName];
                }
            }
            return xsag;
        }

        /// <summary>
        /// This function is called recursively to create/update objects of a schema
        /// </summary>
        /// <param name="xsSet"></param>
        /// <param name="typeName"></param>
        /// <param name="inputSchemaObject"></param>
        /// <param name="addToSchema"></param>
        /// <param name="metaType"></param>
        /// <param name="schemaHash"></param>
        /// <param name="mappedTypeHash"></param>
        /// <param name="referenceID"></param>
        private static void CollectSchemaTypes(XmlSchemaSet xsSet, XmlQualifiedName typeName, XmlSchemaObject inputSchemaObject, bool addToSchema,
                                DTO.SchemaObjectType metaType, Dictionary<string, Guid> schemaHash, Dictionary<string, Guid> mappedTypeHash,
                                Guid referenceID, SqlTransaction txn, SqlConnection conn)
        {
            if (inputSchemaObject == null)
            {
                switch (metaType)
                {
                    case DTO.SchemaObjectType.Element:
                        inputSchemaObject = xsSet.GlobalElements[typeName];
                        break;

                    case DTO.SchemaObjectType.Attribute:
                        inputSchemaObject = xsSet.GlobalAttributes[typeName];
                        break;

                    case DTO.SchemaObjectType.AttributeGroup:
                        inputSchemaObject = GetAttributeFromSchmea(xsSet, typeName); ;
                        break;

                    case DTO.SchemaObjectType.ComplexType:
                    case DTO.SchemaObjectType.SimpleType:
                    case DTO.SchemaObjectType.Unknown:
                        inputSchemaObject = xsSet.GlobalTypes[typeName];
                        metaType = GetSchemaObjectType(inputSchemaObject);
                        break;
                }
            }
            if (typeName != null && addToSchema == true)
            {
                bool found = false;
                referenceID = SaveSchemaObjectToDatabase(typeName, referenceID, inputSchemaObject, metaType, schemaHash, mappedTypeHash, txn, conn, out found);
                // SchemaObject arealy exists 
                if (found == true) return;
            }
            if (inputSchemaObject != null)
            {
                #region XmlSchemaAttribute

                if (inputSchemaObject is XmlSchemaAttribute)
                {
                    XmlSchemaAttribute xsAttribute = inputSchemaObject as XmlSchemaAttribute;
                    if (xsAttribute.RefName != null && xsAttribute.RefName.IsEmpty == false)
                    {
                        CollectSchemaTypes(xsSet, xsAttribute.RefName, null, true, DTO.SchemaObjectType.Attribute, schemaHash, mappedTypeHash, referenceID, txn, conn);
                    }
                    else
                    {
                        if (xsAttribute.SchemaTypeName != null)
                        {
                            CollectSchemaTypes(xsSet, xsAttribute.SchemaTypeName, null, true, DTO.SchemaObjectType.Unknown, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                        else
                        {
                            if (xsAttribute.SchemaType != null)
                            {
                                CollectSchemaTypes(xsSet, null, xsAttribute.SchemaType, false, DTO.SchemaObjectType.Unknown, schemaHash, mappedTypeHash, referenceID, txn, conn);
                            }
                        }
                    }
                    return;
                }

                #endregion XmlSchemaAttribute

                #region XmlSchemaAttributeGroup

                if (inputSchemaObject is XmlSchemaAttributeGroup)
                {
                    XmlSchemaAttributeGroup xsAttributeGroup = inputSchemaObject as XmlSchemaAttributeGroup;
                    foreach (XmlSchemaObject attributeObject in xsAttributeGroup.Attributes)
                    {
                        if (attributeObject is XmlSchemaAttributeGroupRef)
                        {
                            XmlSchemaAttributeGroupRef xsGroupRef = attributeObject as XmlSchemaAttributeGroupRef;
                            CollectSchemaTypes(xsSet, xsGroupRef.RefName, null, true, DTO.SchemaObjectType.AttributeGroup, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                        else
                            CollectSchemaTypes(xsSet, null, attributeObject, false, DTO.SchemaObjectType.Attribute, schemaHash, mappedTypeHash, referenceID, txn, conn);
                    }
                    return;
                }

                #endregion XmlSchemaAttributeGroup

                #region XmlSchemaSimpleType

                if (inputSchemaObject is XmlSchemaSimpleType)
                {
                    XmlSchemaSimpleType xsSimpleType = inputSchemaObject as XmlSchemaSimpleType;
                    CollectSchemaTypes(xsSet, null, xsSimpleType.Content, false, DTO.SchemaObjectType.Unknown, schemaHash, mappedTypeHash, referenceID, txn, conn);
                    return;
                }

                #endregion XmlSchemaSimpleType

                #region XmlSchemaSimpleTypeUnion

                if (inputSchemaObject is XmlSchemaSimpleTypeUnion)
                {
                    XmlSchemaSimpleTypeUnion xsSimpleTypeUnion = inputSchemaObject as XmlSchemaSimpleTypeUnion;

                    if (xsSimpleTypeUnion.BaseTypes != null)
                    {
                        foreach (XmlSchemaObject unionObject in xsSimpleTypeUnion.BaseTypes)
                        {
                            CollectSchemaTypes(xsSet, null, unionObject, false, DTO.SchemaObjectType.Unknown, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                    }
                    if (xsSimpleTypeUnion.MemberTypes != null)
                    {
                        foreach (XmlQualifiedName qName in xsSimpleTypeUnion.MemberTypes)
                        {
                            CollectSchemaTypes(xsSet, qName, null, true, DTO.SchemaObjectType.Unknown, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                    }
                    return;
                }

                #endregion XmlSchemaSimpleTypeUnion

                #region XmlSchemaSimpleTypeList

                if (inputSchemaObject is XmlSchemaSimpleTypeList)
                {
                    XmlSchemaSimpleTypeList xsSimpleTypeList = inputSchemaObject as XmlSchemaSimpleTypeList;

                    if (xsSimpleTypeList.ItemTypeName != null)
                    {
                        CollectSchemaTypes(xsSet, xsSimpleTypeList.ItemTypeName, null, true, DTO.SchemaObjectType.Unknown, schemaHash, mappedTypeHash, referenceID, txn, conn);
                    }
                    return;
                }

                #endregion XmlSchemaSimpleTypeList

                #region XmlSchemaSimpleTypeRestriction

                if (inputSchemaObject is XmlSchemaSimpleTypeRestriction)
                {
                    XmlSchemaSimpleTypeRestriction xsSimpleTypeRestriction = inputSchemaObject as XmlSchemaSimpleTypeRestriction;

                    if (xsSimpleTypeRestriction.BaseTypeName != null)
                    {
                        CollectSchemaTypes(xsSet, xsSimpleTypeRestriction.BaseTypeName, null, true, DTO.SchemaObjectType.Unknown, schemaHash, mappedTypeHash, referenceID, txn, conn);
                    }
                    return;
                }

                #endregion XmlSchemaSimpleTypeRestriction

                #region XmlSchemaSimpleContentExtension

                if (inputSchemaObject is XmlSchemaSimpleContentExtension)
                {
                    XmlSchemaSimpleContentExtension xsSimpleContentExtension = inputSchemaObject as XmlSchemaSimpleContentExtension;

                    CollectSchemaTypes(xsSet, xsSimpleContentExtension.BaseTypeName, null, true, DTO.SchemaObjectType.Unknown, schemaHash, mappedTypeHash, referenceID, txn, conn);

                    foreach (XmlSchemaObject attributeObject in xsSimpleContentExtension.Attributes)
                    {
                        if (attributeObject is XmlSchemaAttribute)
                        {
                            XmlSchemaAttribute xsAttribute = attributeObject as XmlSchemaAttribute;
                            if (xsAttribute.RefName != null && xsAttribute.RefName.IsEmpty == false)
                            {
                                CollectSchemaTypes(xsSet, xsAttribute.RefName, null, true, DTO.SchemaObjectType.Attribute, schemaHash, mappedTypeHash, referenceID, txn, conn);
                            }
                            else if (xsAttribute.SchemaTypeName != null)
                            {
                                CollectSchemaTypes(xsSet, xsAttribute.SchemaTypeName, null, true, DTO.SchemaObjectType.Unknown, schemaHash, mappedTypeHash, referenceID, txn, conn);
                            }
                        }
                        else if (attributeObject is XmlSchemaAttributeGroupRef)
                        {
                            XmlSchemaAttributeGroupRef xsAttributeGroupRef = attributeObject as XmlSchemaAttributeGroupRef;
                            CollectSchemaTypes(xsSet, xsAttributeGroupRef.RefName, null, true, DTO.SchemaObjectType.AttributeGroup, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                    }
                    return;
                }

                #endregion XmlSchemaSimpleContentExtension

                #region XmlSchemaSimpleContentRestriction

                if (inputSchemaObject is XmlSchemaSimpleContentRestriction)
                {
                    XmlSchemaSimpleContentRestriction xsSimpleContentRestriction = inputSchemaObject as XmlSchemaSimpleContentRestriction;
                    CollectSchemaTypes(xsSet, xsSimpleContentRestriction.BaseTypeName, null, true, DTO.SchemaObjectType.Unknown, schemaHash, mappedTypeHash, referenceID, txn, conn);

                    foreach (XmlSchemaObject attributeObject in xsSimpleContentRestriction.Attributes)
                    {
                        if (attributeObject is XmlSchemaAttribute)
                        {
                            XmlSchemaAttribute xsAttribute = attributeObject as XmlSchemaAttribute;
                            if (xsAttribute.RefName != null && xsAttribute.RefName.IsEmpty == false)
                            {
                                CollectSchemaTypes(xsSet, xsAttribute.RefName, null, true, DTO.SchemaObjectType.Attribute, schemaHash, mappedTypeHash, referenceID, txn, conn);
                            }
                            else if (xsAttribute.SchemaTypeName != null)
                            {
                                CollectSchemaTypes(xsSet, xsAttribute.SchemaTypeName, null, true, DTO.SchemaObjectType.Unknown, schemaHash, mappedTypeHash, referenceID, txn, conn);
                            }
                        }
                        else if (attributeObject is XmlSchemaAttributeGroupRef)
                        {
                            XmlSchemaAttributeGroupRef xsAttributeGroupRef = attributeObject as XmlSchemaAttributeGroupRef;
                            CollectSchemaTypes(xsSet, xsAttributeGroupRef.RefName, null, true, DTO.SchemaObjectType.AttributeGroup, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                    }
                    return;
                }

                #endregion XmlSchemaSimpleContentRestriction

                #region XmlSchemaComplexContentExtension

                if (inputSchemaObject is XmlSchemaComplexContentExtension)
                {
                    XmlSchemaComplexContentExtension xsComplexContentExtension = inputSchemaObject as XmlSchemaComplexContentExtension;
                    CollectSchemaTypes(xsSet, xsComplexContentExtension.BaseTypeName, null, true, DTO.SchemaObjectType.Unknown, schemaHash, mappedTypeHash, referenceID, txn, conn);

                    foreach (XmlSchemaObject attributeObject in xsComplexContentExtension.Attributes)
                    {
                        if (attributeObject is XmlSchemaAttribute)
                        {
                            XmlSchemaAttribute xsAttribute = attributeObject as XmlSchemaAttribute;
                            if (xsAttribute.RefName != null && xsAttribute.RefName.IsEmpty == false)
                            {
                                CollectSchemaTypes(xsSet, xsAttribute.RefName, null, true, DTO.SchemaObjectType.Attribute, schemaHash, mappedTypeHash, referenceID, txn, conn);
                            }
                            else if (xsAttribute.SchemaTypeName != null)
                            {
                                CollectSchemaTypes(xsSet, xsAttribute.SchemaTypeName, null, true, DTO.SchemaObjectType.Unknown, schemaHash, mappedTypeHash, referenceID, txn, conn);
                            }
                        }
                        else if (attributeObject is XmlSchemaAttributeGroupRef)
                        {
                            XmlSchemaAttributeGroupRef xsAttributeGroupRef = attributeObject as XmlSchemaAttributeGroupRef;
                            CollectSchemaTypes(xsSet, xsAttributeGroupRef.RefName, null, true, DTO.SchemaObjectType.AttributeGroup, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                    }
                    if (xsComplexContentExtension.Particle != null)
                    {
                        if (xsComplexContentExtension.Particle is XmlSchemaSequence)
                        {
                            XmlSchemaSequence xsSequence = xsComplexContentExtension.Particle as XmlSchemaSequence;
                            CollectSchemaTypes(xsSet, null, xsSequence, false, DTO.SchemaObjectType.Element, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                        else if (xsComplexContentExtension.Particle is XmlSchemaChoice)
                        {
                            XmlSchemaChoice xsChoice = xsComplexContentExtension.Particle as XmlSchemaChoice;
                            CollectSchemaTypes(xsSet, null, xsChoice, false, DTO.SchemaObjectType.Element, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                    }
                    return;
                }

                #endregion XmlSchemaComplexContentExtension

                #region XmlSchemaComplexContentRestriction

                if (inputSchemaObject is XmlSchemaComplexContentRestriction)
                {
                    XmlSchemaComplexContentRestriction xsComplexContentRestriction = inputSchemaObject as XmlSchemaComplexContentRestriction;
                    CollectSchemaTypes(xsSet, xsComplexContentRestriction.BaseTypeName, null, true, DTO.SchemaObjectType.Unknown, schemaHash, mappedTypeHash, referenceID, txn, conn);

                    foreach (XmlSchemaObject attributeObject in xsComplexContentRestriction.Attributes)
                    {
                        if (attributeObject is XmlSchemaAttribute)
                        {
                            XmlSchemaAttribute xsAttribute = attributeObject as XmlSchemaAttribute;
                            if (xsAttribute.RefName != null && xsAttribute.RefName.IsEmpty == false)
                            {
                                CollectSchemaTypes(xsSet, xsAttribute.RefName, null, true, DTO.SchemaObjectType.Attribute, schemaHash, mappedTypeHash, referenceID, txn, conn);
                            }
                            else if (xsAttribute.SchemaTypeName != null)
                            {
                                CollectSchemaTypes(xsSet, xsAttribute.SchemaTypeName, null, true, DTO.SchemaObjectType.Unknown, schemaHash, mappedTypeHash, referenceID, txn, conn);
                            }
                        }
                        else if (attributeObject is XmlSchemaAttributeGroupRef)
                        {
                            XmlSchemaAttributeGroupRef xsAttributeGroupRef = attributeObject as XmlSchemaAttributeGroupRef;
                            CollectSchemaTypes(xsSet, xsAttributeGroupRef.RefName, null, true, DTO.SchemaObjectType.AttributeGroup, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                    }
                    return;
                }

                #endregion XmlSchemaComplexContentRestriction

                #region XmlSchemaElement

                if (inputSchemaObject is XmlSchemaElement)
                {
                    XmlSchemaElement xsElement = inputSchemaObject as XmlSchemaElement;
                    if (xsElement.RefName != null && xsElement.RefName.IsEmpty == false)
                    {
                        CollectSchemaTypes(xsSet, xsElement.RefName, null, true, DTO.SchemaObjectType.Element, schemaHash, mappedTypeHash, referenceID, txn, conn);
                    }
                    else
                    {
                        if (xsElement.SchemaType != null)
                        {
                            CollectSchemaTypes(xsSet, null, xsElement.SchemaType, false, DTO.SchemaObjectType.Unknown, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                        else
                        {
                            if (xsElement.SchemaTypeName != null)
                            {
                                CollectSchemaTypes(xsSet, xsElement.SchemaTypeName, null, true, DTO.SchemaObjectType.Unknown, schemaHash, mappedTypeHash, referenceID, txn, conn);
                            }
                        }
                    }
                    return;
                }

                #endregion XmlSchemaElement

                #region XmlSchemaComplexType

                if (inputSchemaObject is XmlSchemaComplexType)
                {
                    XmlSchemaComplexType xsComplexType = inputSchemaObject as XmlSchemaComplexType;
                    foreach (XmlSchemaObject attributeObject in xsComplexType.Attributes)
                    {
                        if (attributeObject is XmlSchemaAttribute)
                        {
                            XmlSchemaAttribute xsAttribute = attributeObject as XmlSchemaAttribute;
                            if (xsAttribute.RefName != null && xsAttribute.RefName.IsEmpty == false)
                            {
                                CollectSchemaTypes(xsSet, xsAttribute.RefName, null, true, DTO.SchemaObjectType.Attribute, schemaHash, mappedTypeHash, referenceID, txn, conn);
                            }
                            else if (xsAttribute.SchemaTypeName != null)
                            {
                                CollectSchemaTypes(xsSet, xsAttribute.SchemaTypeName, null, true, DTO.SchemaObjectType.Unknown, schemaHash, mappedTypeHash, referenceID, txn, conn);
                            }
                        }
                        else if (attributeObject is XmlSchemaAttributeGroupRef)
                        {
                            XmlSchemaAttributeGroupRef xsAttributeGroupRef = attributeObject as XmlSchemaAttributeGroupRef;
                            CollectSchemaTypes(xsSet, xsAttributeGroupRef.RefName, null, true, DTO.SchemaObjectType.AttributeGroup, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                    }
                    if (xsComplexType.Particle != null)
                    {
                        if (xsComplexType.Particle is XmlSchemaSequence)
                        {
                            XmlSchemaSequence xsSequence = xsComplexType.Particle as XmlSchemaSequence;
                            CollectSchemaTypes(xsSet, null, xsSequence, false, DTO.SchemaObjectType.Element, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                        else if (xsComplexType.Particle is XmlSchemaChoice)
                        {
                            XmlSchemaChoice xsChoice = xsComplexType.Particle as XmlSchemaChoice;
                            CollectSchemaTypes(xsSet, null, xsChoice, false, DTO.SchemaObjectType.Element, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                    }
                    else if (xsComplexType.ContentModel != null)
                    {
                        if (xsComplexType.ContentModel is XmlSchemaComplexContent)
                        {
                            XmlSchemaComplexContent xsComplexContent = xsComplexType.ContentModel as XmlSchemaComplexContent;
                            // It is either extension or restriction
                            CollectSchemaTypes(xsSet, null, xsComplexContent.Content, false, DTO.SchemaObjectType.Element, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                        else
                        {
                            XmlSchemaSimpleContent xsSimpleContent = xsComplexType.ContentModel as XmlSchemaSimpleContent;
                            // It is either extension or restriction
                            CollectSchemaTypes(xsSet, null, xsSimpleContent.Content, false, DTO.SchemaObjectType.Element, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                    }
                }

                #endregion XmlSchemaComplexType

                #region XmlSchemaSequence

                if (inputSchemaObject is XmlSchemaSequence)
                {
                    XmlSchemaSequence xsSequence = inputSchemaObject as XmlSchemaSequence;
                    foreach (XmlSchemaObject sequenceObject in xsSequence.Items)
                    {
                        if (sequenceObject is XmlSchemaElement)
                        {
                            XmlSchemaElement xsItemElement = sequenceObject as XmlSchemaElement;
                            CollectSchemaTypes(xsSet, xsItemElement.QualifiedName, xsItemElement, false, DTO.SchemaObjectType.Element, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                        else if (sequenceObject is XmlSchemaSequence)
                        {
                            XmlSchemaSequence xsItemSequence = sequenceObject as XmlSchemaSequence;
                            CollectSchemaTypes(xsSet, null, xsItemSequence, false, DTO.SchemaObjectType.Element, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                        else if (sequenceObject is XmlSchemaGroup)
                        {
                            XmlSchemaGroup xsItemGroup = sequenceObject as XmlSchemaGroup;
                            CollectSchemaTypes(xsSet, xsItemGroup.QualifiedName, xsItemGroup, false, DTO.SchemaObjectType.Element, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                        else
                        {
                            CollectSchemaTypes(xsSet, null, sequenceObject, false, DTO.SchemaObjectType.Element, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                    }
                }

                #endregion XmlSchemaSequence

                #region XmlSchemaChoice

                if (inputSchemaObject is XmlSchemaChoice)
                {
                    XmlSchemaChoice xsChoice = inputSchemaObject as XmlSchemaChoice;
                    foreach (XmlSchemaObject choiceObject in xsChoice.Items)
                    {
                        if (choiceObject is XmlSchemaElement)
                        {
                            XmlSchemaElement xsItemElement = choiceObject as XmlSchemaElement;
                            CollectSchemaTypes(xsSet, xsItemElement.QualifiedName, xsItemElement, false, DTO.SchemaObjectType.Element, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                        else if (choiceObject is XmlSchemaSequence)
                        {
                            XmlSchemaSequence xsItemSequence = choiceObject as XmlSchemaSequence;
                            CollectSchemaTypes(xsSet, null, xsItemSequence, false, DTO.SchemaObjectType.Element, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                        else if (choiceObject is XmlSchemaGroup)
                        {
                            XmlSchemaGroup xsItemGroup = choiceObject as XmlSchemaGroup;
                            CollectSchemaTypes(xsSet, xsItemGroup.QualifiedName, null, false, DTO.SchemaObjectType.Element, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                        else
                        {
                            CollectSchemaTypes(xsSet, null, choiceObject, false, DTO.SchemaObjectType.Element, schemaHash, mappedTypeHash, referenceID, txn, conn);
                        }
                    }
                }

                #endregion XmlSchemaChoice
            }
        }

        private static void CollectRealatedSchemas(DTO.Schema schema, Dictionary<string, Guid> schemaHash, List<Guid> schemaIDs,
                                                    XmlSchemaSet xssImport, SqlTransaction txn, SqlConnection conn)
        {
            try
            {
                Dictionary<string, DTO.Schema> relatedSchemas = new Dictionary<string, DTO.Schema>();
                CollectRealatedSchemas(schema, relatedSchemas, txn, conn);
                foreach (DTO.Schema relatedSchema in relatedSchemas.Values)
                {
                    XmlSchema xs = CatalogSvcHelper.CreateXmlSchemaFromSchema(relatedSchema, false);
                    schemaIDs.Add(relatedSchema.ID);
                    schemaHash.Add(relatedSchema.NamespaceURI, relatedSchema.ID);
                    if (xssImport.Contains(relatedSchema.NamespaceURI) == false)
                        xssImport.Add(xs);
                }
                xssImport.Compile();
            }
            catch (Exception ex)
            {
                throw new ApplicationException(string.Format("Failed to build related XmlSchemaSet for Schema [{0}] due to error [{1}]", schema.NamespaceURI, CatalogSvcHelper.GetExceptionDetails(ex)));
            }
        }
        private static void CollectRealatedSchemas(DTO.Schema schema, Dictionary<string, DTO.Schema> schemaHash,
                                            SqlTransaction txn, SqlConnection conn)
        {
            try
            {
                if (schemaHash.ContainsKey(schema.NamespaceURI) == false)
                {
                    schemaHash.Add(schema.NamespaceURI, schema);
                    if (schema.ImportedSchemas != null && schema.ImportedSchemas.Count > 0)
                    {
                        foreach (DTO.SchemaImport si in schema.ImportedSchemas)
                        {
                            if (schemaHash.ContainsKey(si.NamespaceURI) == false)
                            {
                                DTO.Schema importSchema = GetSchemaByNamespace(si.NamespaceURI, txn, conn);
                                CollectRealatedSchemas(importSchema, schemaHash, txn, conn);
                            }
                        }
                    }
                }
                //if (schema.ID != Guid.Empty)
                //{
                //    DTO.SchemaList schemaList = DataAccess.Schema.ListDependencySchemas(schema.ID, txn, conn);
                //    if (schemaList.Schemas != null && schemaList.Schemas.Count > 0)
                //    {
                //        foreach (DTO.SchemaListElement schemaListElement in schemaList.Schemas)
                //        {
                //            if (schemaHash.ContainsKey(schemaListElement.Name) == false)
                //            {
                //                DTO.Schema dependentSchema = GetSchema(schemaListElement.ID, txn, conn);
                //                schemaHash.Add(schemaListElement.Name, dependentSchema);
                //            }
                //        }
                //    }
                //}
            }
            catch (Exception ex)
            {
                throw new ApplicationException(string.Format("An error occurred while building related schema list from MSE Schema [{0}]", schema.NamespaceURI), ex);
            }
        }
        #endregion

        #endregion

        #region Schema Object private functions

        private static void CreateSchemaObjects(DTO.Schema schema, SqlTransaction txn, SqlConnection conn)
        {
            try
            {
                Dictionary<string, Guid> mappedElemntHash = new Dictionary<string, Guid>();
                Dictionary<string, Guid> schemaHash = new Dictionary<string, Guid>();
                List<Guid> schemaIDs = new List<Guid>();
                XmlSchemaSet xssImport = new XmlSchemaSet();

                XmlSchema xs = null;
                if (schema.Objects != null && schema.Objects.Count > 0)
                    xs = CatalogSvcHelper.CreateXmlSchemaFromSchema(schema, false);
                else
                    xs = CatalogSvcHelper.LoadXmlSchemaFromString(schema.XSD.OuterXml);
                xssImport.Add(xs);
                CollectRealatedSchemas(schema, schemaHash, schemaIDs, xssImport, txn, conn);

                CreateSchemaObjectsFromXmlSchema(xssImport, xs, mappedElemntHash, schemaHash, txn, conn);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(string.Format("An error occurred while creating schema Objects for Schema [{0}]", schema.NamespaceURI), ex);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="elementName"></param>
        /// <param name="parentID"></param>
        /// <param name="xso"></param>
        /// <param name="metaType"></param>
        /// <param name="schemaHash"></param>
        /// <param name="savedElemntHash"></param>
        /// <param name="found"></param>
        /// <returns></returns>
        private static Guid SaveSchemaObjectToDatabase(XmlQualifiedName objectName, Guid parentID, XmlSchemaObject xso, DTO.SchemaObjectType metaType,
                                Dictionary<string, Guid> schemaHash, Dictionary<string, Guid> savedObjectHash, SqlTransaction txn, SqlConnection conn, out bool found)
        {
            Guid objectID = Guid.Empty;
            found = false;
            if (objectName.Namespace != XmlSchema.Namespace)
            {
                if (objectName.Name.Length > 0 && objectName.Namespace.Length > 0)
                {
                    string key = CatalogSvcHelper.CreateKey(objectName, metaType);
                    if (savedObjectHash.ContainsKey(key) == false)
                    {

                        DTO.SchemaObject schemaObject = new DTO.SchemaObject();
                        schemaObject.Xml = SerializeSchemaObject(xso, objectName.Namespace);
                        schemaObject.Name = objectName.Name;
                        schemaObject.Type = metaType;
                        schemaObject.NamespaceUri = objectName.Namespace;

                        List<DTO.SchemaObject> existingSchemaObjects = DataAccess.SchemaObject.ListSchemaObjectByNameTypeAndNamespace(objectName.Namespace, objectName.Name, metaType, txn, conn);
                        DTO.SchemaObject latestSchemaObject = null;
                        if (existingSchemaObjects != null && existingSchemaObjects.Count > 0)
                        {
                            // Get the latest schema object
                            latestSchemaObject = existingSchemaObjects.First(x => x.Revision.IsLatest == true);
                            // Now check if the schema object matches any existing version
                            foreach (DTO.SchemaObject existingSchemaObject in existingSchemaObjects)
                            {
                                if (CheckIfSchemaObjectsEqual(schemaObject, existingSchemaObject) == true)
                                {
                                    // SchemaObject already exists and is the same as the one that we are trying to save
                                    // So no need to do any saves
                                    found = true;
                                    objectID = existingSchemaObject.ID;
                                    break;
                                }
                            }
                            if (found == false)
                            {
                                objectID = DataAccess.SchemaObject.UpdateSchemaObject(schemaObject, latestSchemaObject.ID, parentID, schemaHash[objectName.Namespace], txn, conn);
                            }
                        }
                        else
                        {
                            objectID = DataAccess.SchemaObject.CreateSchemaObject(schemaObject, parentID, schemaHash[objectName.Namespace], txn, conn);
                            schemaObject.ID = objectID;
                            //if (parentID != Guid.Empty)
                            //{
                            //    DataAccess.SchemaObject.CreateSchemaObjectDependency(objectID, parentID, txn, conn);
                            //}
                            // Create a DataEntity for Every SchmeaObject of type Element
                            if (metaType == DTO.SchemaObjectType.Element)
                            {
                                DTO.DataEntity dataEntity = DataEntityManager.CreateDataEntityFromSchemaObject(schemaObject, txn, conn);
                            }
                        }
                        savedObjectHash.Add(key, objectID);
                        if (parentID != Guid.Empty)
                        {
                            DataAccess.SchemaObject.CreateSchemaObjectDependency(objectID, parentID,objectName.Namespace, txn, conn);
                        }
                    }
                    else
                    {
                        objectID = savedObjectHash[key];
                        if (parentID != Guid.Empty)
                        {
                            DataAccess.SchemaObject.CreateSchemaObjectDependency(objectID, parentID, objectName.Namespace, txn, conn);
                        }
                        found = true;
                    }
                }
            }
            return objectID;
        }


        public static bool CheckIfSchemaObjectsEqual(DTO.SchemaObject inputSchemaObject, DTO.SchemaObject existingSchemaObject)
        {
            if (string.Compare(inputSchemaObject.Name, existingSchemaObject.Name, false) == 0 &&
                string.Compare(inputSchemaObject.NamespaceUri, existingSchemaObject.NamespaceUri, false) == 0 &&
                inputSchemaObject.Type == existingSchemaObject.Type &&
                CatalogSvcHelper.XMLCompare(inputSchemaObject.Xml, existingSchemaObject.Xml) == true)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        private static DTO.SchemaObjectType GetSchemaObjectType(XmlSchemaObject xmlSchemaObject)
        {
            if (xmlSchemaObject is XmlSchemaAttribute)
            {
                return DTO.SchemaObjectType.Attribute;
            }
            else if (xmlSchemaObject is XmlSchemaAttributeGroup)
            {
                return DTO.SchemaObjectType.AttributeGroup;
            }
            else if (xmlSchemaObject is XmlSchemaSimpleType)
            {
                return DTO.SchemaObjectType.SimpleType;
            }
            else if (xmlSchemaObject is XmlSchemaComplexType)
            {
                return DTO.SchemaObjectType.ComplexType;
            }
            else
            {
                return DTO.SchemaObjectType.Unknown;
            }
        }

        private static void CreateSchemaObjectsFromXmlSchema(XmlSchemaSet xssImport, XmlSchema xs, Dictionary<string, Guid> mappedElemntHash,
                                                             Dictionary<string, Guid> schemaHash, SqlTransaction txn, SqlConnection conn)
        {
            // Now Save Schema Elements
            foreach (XmlSchemaObject xso in xs.Attributes.Values)
            {
                XmlSchemaAttribute xsa = (XmlSchemaAttribute)xso;
                CollectSchemaTypes(xssImport, xsa.QualifiedName, xsa, true, DTO.SchemaObjectType.Attribute, schemaHash, mappedElemntHash, Guid.Empty, txn, conn);
            }
            foreach (XmlSchemaObject xso in xs.AttributeGroups.Values)
            {
                XmlSchemaAttributeGroup xsag = (XmlSchemaAttributeGroup)xso;
                CollectSchemaTypes(xssImport, xsag.QualifiedName, xsag, true, DTO.SchemaObjectType.AttributeGroup, schemaHash, mappedElemntHash, Guid.Empty, txn, conn);
            }
            foreach (XmlSchemaObject xso in xs.SchemaTypes.Values)
            {
                XmlSchemaType xst = (XmlSchemaType)xso;
                CollectSchemaTypes(xssImport, xst.QualifiedName, xst, true, GetSchemaObjectType(xso), schemaHash, mappedElemntHash, Guid.Empty, txn, conn);
            }
            foreach (XmlSchemaObject xso in xs.Elements.Values)
            {
                XmlSchemaElement xse = (XmlSchemaElement)xso;
                CollectSchemaTypes(xssImport, xse.QualifiedName, xse, true, DTO.SchemaObjectType.Element, schemaHash, mappedElemntHash, Guid.Empty, txn, conn);
            }
        }

        #region SchemaObject Import/Export Functions

        public static void SaveSchemasFromImport(List<DTO.Schema> schemas)
        {
            using (SqlConnection conn = CatalogSvcHelper.GetConnection())
            {
                conn.Open();
                SqlTransaction txn = CatalogSvcHelper.GetTransaction(conn, IsolationLevel.ReadCommitted);

                try
                {

                    Dictionary<Guid, Guid> schemaObjectIDMap = new Dictionary<Guid, Guid>();

                    // First create all the Schema containers, Imports and Schema Objects
                    foreach (DTO.Schema schema in schemas)
                    {
                        schema.ID = DataAccess.Schema.CreateSchemaNamespace(schema, txn, conn);

                        if (schema.ImportedSchemas != null && schema.ImportedSchemas.Count > 0)
                        {
                            foreach (DTO.SchemaImport import in schema.ImportedSchemas)
                            {
                                DataAccess.SchemaImport.CreateSchemaImport(schema.ID, import, txn, conn);
                            }
                        }
                        // Now create all the SchemaObjects
                        foreach (DTO.SchemaObject schemaObject in schema.Objects)
                        {
                            SaveSchemaObjectFromImport(schemaObject,schema.ID, Guid.Empty, schemaObjectIDMap, txn, conn);
                        }
                    }
                    // Now let's update dependencies for each SchemaObject
                    foreach (DTO.Schema schema in schemas)
                    {
                        foreach (DTO.SchemaObject schemaObject in schema.Objects)
                        {
                            if (schemaObject.Dependencies != null &&
                                schemaObject.Dependencies.SchemaObjects != null &&
                                schemaObject.Dependencies.SchemaObjects.Count > 0)
                            {
                                foreach (DTO.SchemaObjectListElement sole in schemaObject.Dependencies.SchemaObjects)
                                {
                                    Guid itemID = sole.ID;
                                    if (schemaObjectIDMap.ContainsKey(sole.ID) == true)
                                        itemID = schemaObjectIDMap[sole.ID];
                                    Data.SchemaObject.CreateSchemaObjectDependency(itemID, schemaObject.ID, sole.NamespaceUri, txn, conn);
                                }
                            }
                        }
                    }
                    if (txn != null) txn.Commit();
                }
                catch (Exception)
                {
                    if (txn != null) txn.Rollback();
                    throw;
                }
            }
        }
        private static DTO.SchemaObject SaveSchemaObjectFromImport(DTO.SchemaObject schemaObject, Guid schemaID, Guid parentID, Dictionary<Guid, Guid> schemaObjectIDMap, SqlTransaction txn, SqlConnection conn)
        {
            DTO.SchemaObject currentSchemaObject = null;

            
            if (string.IsNullOrEmpty(schemaObject.NamespaceUri) == false)
            {
                Guid existingID = schemaObject.ID;
                bool hasItems = false;
                // Check if SchemaObject already Exists
                currentSchemaObject = GetEquivalentSchemaObject(schemaObject,ref hasItems, txn, conn);

                if (currentSchemaObject != null)
                {
                    if (currentSchemaObject.ID == schemaObject.ID)
                    {
                        // We got a match 
                        // We do not have to do anything
                    }
                    else
                    {
                        // We got  match but the IDs are different
                        // Just add the new ID to map
                        if (schemaObjectIDMap.ContainsKey(existingID) == false)
                        {
                            schemaObjectIDMap.Add(existingID, currentSchemaObject.ID);
                            schemaObject.ID = currentSchemaObject.ID;
                        }
                    }
                }
                else
                {
                    // No match was found 
                    // But check if SchemaObject of same name, type and namespaceUri is there 
                    if (hasItems == true)
                    {
                        // We have to update the existing schema object
                        Guid newID = Data.SchemaObject.UpdateSchemaObject(schemaObject, currentSchemaObject.ID, parentID, schemaID, txn, conn);
                        schemaObjectIDMap.Add(existingID, newID);
                        schemaObject.ID = newID;
                    }
                    else
                    {
                        // We have to create the new schema object
                        Guid newID = Data.SchemaObject.CreateSchemaObject(schemaObject, parentID, schemaID, txn, conn);
                        schemaObjectIDMap.Add(existingID, newID);
                        schemaObject.ID = newID;
                    }
                }
                // If the Schema Object is of type Element then ensure to create/associate to a DataEntity
                if (schemaObject.Type == DTO.SchemaObjectType.Element)
                {
                    string dataEntityName = string.Format("{0}:{1}", schemaObject.Name, schemaObject.NamespaceUri);

                    Guid dataEntityID = DataAccess.Entity.GetIDFromName(dataEntityName, DTO.EntityClass.DataEntity, txn, conn);
                    if (dataEntityID == Guid.Empty)
                    {
                        DTO.DataEntity dataEntity = new DTO.DataEntity();
                        dataEntity.Name = dataEntityName;
                        dataEntity.SchemaObjects = new List<DTO.SchemaObject>();
                        dataEntity.SchemaObjects.Add(schemaObject);
                        dataEntity = DataAccess.DataEntity.CreateDataEntity(dataEntity, txn, conn);
                        dataEntityID = dataEntity.ID;
                    }
                    DataAccess.DataEntity.AssociateSchemaObjectToDataEntity(dataEntityID, schemaObject.Name, schemaID, txn, conn);
                }
            }
            else
            {
                throw new ApplicationException(string.Format("Invalid SchemaObject with Name=[{0}] is missing the Namespace member", schemaObject.Name));
            }
            return currentSchemaObject;
        }

        public static List<DTO.Schema> ListSchemasForExport(List<DTO.Entity> entities)
        {
            List<DTO.Schema> schemaList = null;
            try
            {


                Dictionary<Guid, Guid> topSchemaObjectIDs = new Dictionary<Guid, Guid>();
                Dictionary<string, DTO.Schema> schemaHash = new Dictionary<string, DTO.Schema>();
                Dictionary<Guid, Guid> schemaObjectIDHash = new Dictionary<Guid, Guid>();

                if (entities == null)
                {
                    DTO.RuntimeServerList runtimeServers = RuntimeServerManager.ListRuntimeServers(null, null);
                    if (runtimeServers != null &&
                        runtimeServers.RuntimeServers != null &&
                        runtimeServers.RuntimeServers.Count > 0)
                    {
                        entities = new List<DTO.Entity>();
                        runtimeServers.RuntimeServers.ForEach(x => entities.Add(new DTO.Entity
                                                            {
                                                                ID = x.ID,
                                                                Name = x.Name,
                                                                EntityClass = DTO.EntityClass.RuntimeServer
                                                            }));
                    }
                }
                if (entities != null && entities.Count > 0)
                {
                    BuildListOfTopLevelSchemaObjects(entities, topSchemaObjectIDs);
                    if (topSchemaObjectIDs.Count > 0)
                    {
                        foreach (Guid schemaObjectID in topSchemaObjectIDs.Keys)
                        {
                            LoadDependentSchemaObjects(schemaObjectID,schemaObjectIDHash, schemaHash);
                        }
                        if (schemaHash.Count > 0)
                        {
                            schemaList = schemaHash.Values.ToList();
                        }
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }

            return schemaList;
        }

        private static void LoadDependentSchemaObjects(Guid schemaObjectID, Dictionary<Guid,Guid> schemaObjectIDHash,
                                                        Dictionary<string, DTO.Schema> schemaHash)
        {
            // Add the SchemaObject to hash if it does not exist
            if (schemaObjectIDHash.ContainsKey(schemaObjectID) == false)
            {
                schemaObjectIDHash.Add(schemaObjectID, schemaObjectID);
                DTO.SchemaObject schemaObject = SchemaManager.GetSchemaObjectByID(schemaObjectID, true);
                DTO.Schema schema = null;
                if (schemaHash.ContainsKey(schemaObject.NamespaceUri) == false)
                {
                    Guid schemaID = DataAccess.Entity.GetIDFromName(schemaObject.NamespaceUri,DTO.EntityClass.Schema,null,null);
                    schema = DataAccess.Schema.GetSchema(schemaID, null, null);
                    schema.Objects = new List<DTO.SchemaObject>();
                    schemaHash.Add(schemaObject.NamespaceUri, schema);
                }
                schemaHash[schemaObject.NamespaceUri].Objects.Add(schemaObject);

                if (schemaObject.Dependencies != null && schemaObject.Dependencies.SchemaObjects != null)
                {
                    foreach (DTO.SchemaObjectListElement sole in schemaObject.Dependencies.SchemaObjects)
                    {
                        LoadDependentSchemaObjects(sole.ID, schemaObjectIDHash, schemaHash);
                    }
                }
            }
            else
            {
                // Do nothing as the SchemaObject is already there
            }

        }

        private static void BuildListOfTopLevelSchemaObjects(List<DTO.Entity> entities, Dictionary<Guid, Guid> topSchemaObjectIDs)
        {
            if (entities != null && entities.Count > 0)
            {
                List<Guid> processedEntities = new List<Guid>();
                
                foreach (DTO.Entity entity in entities)
                {
                    BuildListOfTopLevelSchemaObjectsFromEntity(entity.ID, entity.EntityClass, topSchemaObjectIDs, processedEntities);
                }
            }
        }

        private static void BuildListOfTopLevelSchemaObjectsFromEntity(Guid entityID,DTO.EntityClass entityClass, Dictionary<Guid, Guid> topSchemaObjectIDs, List<Guid> processedEntities)
        {
            // Check if that entity guid is already processed
            if (processedEntities.Contains(entityID) == false)
            {
                // add it to the list
                processedEntities.Add(entityID);

                switch (entityClass)
                {
                    case DTO.EntityClass.AssertionType:
                        DTO.AssertionType assertionType = PolicyManager.GetAssertionType(entityID, null, null);
                        if (topSchemaObjectIDs.ContainsKey(assertionType.SchemaObject.ID) == false)
                        {
                            topSchemaObjectIDs.Add(assertionType.SchemaObject.ID, assertionType.SchemaObject.ID);
                        }
                        break;

                    case DTO.EntityClass.DataEntity:
                        DTO.DataEntity dataEntity = DataEntityManager.GetDataEntity(entityID);
                        foreach (DTO.SchemaObject schemaObject in dataEntity.SchemaObjects)
                        {
                            if (topSchemaObjectIDs.ContainsKey(schemaObject.ID) == false)
                            {
                                topSchemaObjectIDs.Add(schemaObject.ID, schemaObject.ID);
                            }
                        }
                        processedEntities.Add(entityID);
                        break;

                    case DTO.EntityClass.Endpoint:
                        DTO.Endpoint endPoint = EndpointManager.GetEndpoint(entityID, Guid.Empty, false, null, null);
                        if (endPoint.AssocOpVersionsList != null && endPoint.AssocOpVersionsList.OperationVersions != null)
                        {
                            foreach (DTO.OperationVersionListElement ople in endPoint.AssocOpVersionsList.OperationVersions)
                            {
                                BuildListOfTopLevelSchemaObjectsFromEntity(ople.ID, DTO.EntityClass.OperationVersion, topSchemaObjectIDs, processedEntities);
                            }
                        }
                        if (endPoint.PubOpVersionsList != null && endPoint.PubOpVersionsList.OperationVersions != null)
                        {
                            foreach (DTO.OperationVersionListElement ople in endPoint.PubOpVersionsList.OperationVersions)
                            {
                                BuildListOfTopLevelSchemaObjectsFromEntity(ople.ID, DTO.EntityClass.OperationVersion, topSchemaObjectIDs, processedEntities);
                            }
                        }
                        if (endPoint.Policy != null)
                        {
                            BuildListOfTopLevelSchemaObjectsFromEntity(endPoint.Policy.ID, DTO.EntityClass.Policy, topSchemaObjectIDs, processedEntities);
                        }
                        break;

                    case DTO.EntityClass.OperationVersion:
                        DTO.OperationVersion operationVersion = OperationManager.GetOperationVersion(entityID , null, null);
                        if (operationVersion.RequestMsg != null && operationVersion.RequestMsg.Count > 0)
                        {
                            foreach (DTO.MessagePart mp in operationVersion.RequestMsg)
                            {
                                if (topSchemaObjectIDs.ContainsKey(mp.SchemaObject.ID) == false)
                                {
                                    topSchemaObjectIDs.Add(mp.SchemaObject.ID, mp.SchemaObject.ID);
                                }
                            }
                        }
                        if (operationVersion.ResponseMsg != null && operationVersion.ResponseMsg.Count > 0)
                        {
                            foreach (DTO.MessagePart mp in operationVersion.ResponseMsg)
                            {
                                if (topSchemaObjectIDs.ContainsKey(mp.SchemaObject.ID) == false)
                                {
                                    topSchemaObjectIDs.Add(mp.SchemaObject.ID, mp.SchemaObject.ID);
                                }
                            }
                        }
                        if (operationVersion.RequestHeaders != null && operationVersion.RequestHeaders.Count > 0)
                        {
                            foreach (DTO.MessageHeader mh in operationVersion.RequestHeaders)
                            {
                                if (topSchemaObjectIDs.ContainsKey(mh.SchemaObject.ID) == false)
                                {
                                    topSchemaObjectIDs.Add(mh.SchemaObject.ID, mh.SchemaObject.ID);
                                }
                            }
                        }
                        if (operationVersion.ResponseHeaders != null && operationVersion.ResponseHeaders.Count > 0)
                        {
                            foreach (DTO.MessageHeader mh in operationVersion.ResponseHeaders)
                            {
                                if (topSchemaObjectIDs.ContainsKey(mh.SchemaObject.ID) == false)
                                {
                                    topSchemaObjectIDs.Add(mh.SchemaObject.ID, mh.SchemaObject.ID);
                                }
                            }
                        }
                        if (operationVersion.SoapFaults != null && operationVersion.SoapFaults.Count > 0)
                        {
                            foreach (DTO.SoapFault sf in operationVersion.SoapFaults)
                            {
                                if (topSchemaObjectIDs.ContainsKey(sf.SchemaObject.ID) == false)
                                {
                                    topSchemaObjectIDs.Add(sf.SchemaObject.ID, sf.SchemaObject.ID);
                                }
                            }
                        }
                        if (operationVersion.Resource != null)
                        {
                            BuildListOfTopLevelSchemaObjectsFromEntity(operationVersion.Resource.ID, DTO.EntityClass.Resource, topSchemaObjectIDs, processedEntities);
                        }
                        if (operationVersion.Policy != null)
                        {
                            BuildListOfTopLevelSchemaObjectsFromEntity(operationVersion.Policy.ID, DTO.EntityClass.Policy, topSchemaObjectIDs, processedEntities);
                        }
                        break;

                    case DTO.EntityClass.Operation:
                        DTO.Operation operation = OperationManager.GetOperation(entityID, null, null);
                        if (operation.Versions != null && operation.Versions.Count > 0)
                        {
                            foreach (DTO.OperationVersion ov in operation.Versions)
                            {
                                BuildListOfTopLevelSchemaObjectsFromEntity(ov.ID, DTO.EntityClass.OperationVersion, topSchemaObjectIDs, processedEntities);
                            }
                        }
                        break;

                    case DTO.EntityClass.Policy:
                        DTO.Policy policy = PolicyManager.GetPolicy(entityID, null, null);
                        if (policy.PolicyAssertions != null && policy.PolicyAssertions.Count > 0)
                        {
                            foreach (DTO.PolicyAssertion pa in policy.PolicyAssertions)
                            {
                                if (topSchemaObjectIDs.ContainsKey(pa.AssertionType.SchemaObject.ID) == false)
                                {
                                    topSchemaObjectIDs.Add(pa.AssertionType.SchemaObject.ID, pa.AssertionType.SchemaObject.ID);
                                }
                            }
                        }
                        break;

                    case DTO.EntityClass.PolicyAssertion:
                        DTO.PolicyAssertion policyAssertion = PolicyManager.GetPolicyAssertion(entityID, null, null);

                        if (topSchemaObjectIDs.ContainsKey(policyAssertion.AssertionType.SchemaObject.ID) == false)
                        {
                            topSchemaObjectIDs.Add(policyAssertion.AssertionType.SchemaObject.ID, policyAssertion.AssertionType.SchemaObject.ID);
                        }
                        break;

                    case DTO.EntityClass.Resource:
                        DTO.Resource resource = DataAccess.Resource.GetResource(entityID, false, null, null, null);
                        if (resource.RequestSchemaObject != null)
                        {
                            if (topSchemaObjectIDs.ContainsKey(resource.RequestSchemaObject.ID) == false)
                            {
                                topSchemaObjectIDs.Add(resource.RequestSchemaObject.ID, resource.RequestSchemaObject.ID);
                            }
                        }
                        if (resource.ResponseSchemaObject != null)
                        {
                            if (topSchemaObjectIDs.ContainsKey(resource.ResponseSchemaObject.ID) == false)
                            {
                                topSchemaObjectIDs.Add(resource.ResponseSchemaObject.ID, resource.ResponseSchemaObject.ID);
                            }
                        }
                        if (resource.Policy != null)
                        {
                            BuildListOfTopLevelSchemaObjectsFromEntity(resource.Policy.ID, DTO.EntityClass.Policy, topSchemaObjectIDs, processedEntities);
                        }
                        if (resource.InstanceID != Guid.Empty)
                        {
                            BuildListOfTopLevelSchemaObjectsFromEntity(resource.InstanceID, DTO.EntityClass.SystemInstance, topSchemaObjectIDs, processedEntities);
                        }

                        break;

                    case DTO.EntityClass.RuntimeServer:
                        DTO.RuntimeServer runtimeServer = RuntimeServerManager.GetRuntimeServer(entityID, false, null, null);
                        if (runtimeServer.Endpoints != null && runtimeServer.Endpoints.Count > 0)
                        {
                            foreach (DTO.Endpoint ep in runtimeServer.Endpoints)
                            {
                                BuildListOfTopLevelSchemaObjectsFromEntity(ep.ID, DTO.EntityClass.Endpoint, topSchemaObjectIDs, processedEntities);
                            }
                        }
                        if (runtimeServer.Policy != null)
                        {
                            BuildListOfTopLevelSchemaObjectsFromEntity(runtimeServer.Policy.ID, DTO.EntityClass.Policy, topSchemaObjectIDs, processedEntities);
                        }
                        break;

                    case DTO.EntityClass.SystemInstance:
                        DTO.SystemInstance systemInstance = SystemsManager.GetSystemInstance(entityID, null, null);
                        if (systemInstance.Policy != null)
                        {
                            BuildListOfTopLevelSchemaObjectsFromEntity(systemInstance.Policy.ID, DTO.EntityClass.Policy, topSchemaObjectIDs, processedEntities);
                        }
                        if (systemInstance.SystemID != Guid.Empty)
                        {
                            BuildListOfTopLevelSchemaObjectsFromEntity(systemInstance.SystemID, DTO.EntityClass.System, topSchemaObjectIDs, processedEntities);
                        }
                        break;

                    case DTO.EntityClass.System:
                        DTO.System system = SystemsManager.GetSystem(entityID, null, null);
                        if (system.Policy != null)
                        {
                            BuildListOfTopLevelSchemaObjectsFromEntity(system.Policy.ID, DTO.EntityClass.Policy, topSchemaObjectIDs, processedEntities);
                        }
                        break;
                }
            }
        }

        #endregion

        #endregion


        #region Schema Group functions

        public static DTO.SchemaGroup CreateSchemaGroup(DTO.SchemaGroup schemaGroup)
        {

            using (SqlConnection conn = CatalogSvcHelper.GetConnection())
            {
                conn.Open();
                SqlTransaction txn = CatalogSvcHelper.GetTransaction(conn, IsolationLevel.Snapshot);

                try
                {

                    schemaGroup.ID = DataAccess.Entity.CreateEntityGroup(schemaGroup.Name, schemaGroup.Description, 9, txn, conn);

                    if (schemaGroup.Schemas != null)
                    {
                        foreach (DTO.SchemaListElement schema in schemaGroup.Schemas)
                        {
                            DataAccess.Entity.AssignEntityToEntityGroup(schemaGroup.ID, schema.ID, txn, conn);
                        }
                    }

                    if (txn != null) txn.Commit(); //Commit transaction
                }
                catch (Exception)
                {
                    if (txn != null) txn.Rollback(); //Rollback transaction
                    throw;
                }
            } //Connection is disposed here

            return schemaGroup;
        }

        public static DTO.SchemaGroup UpdateSchemaGroup(DTO.SchemaGroup schemaGroup)
        {
            using (SqlConnection conn = CatalogSvcHelper.GetConnection())
            {
                conn.Open();
                SqlTransaction txn = CatalogSvcHelper.GetTransaction(conn, IsolationLevel.Snapshot);

                try
                {

                    DataAccess.Entity.UpdateEntityGroup(schemaGroup.ID, schemaGroup.Name, schemaGroup.Description, txn, conn);


                    List<DTO.SchemaListElement> oldList = DataAccess.Schema.ListSchemasByGroup(schemaGroup.ID, txn, conn);
                    /// Delete all items from the old list
                    if (oldList != null)
                    {
                        foreach (DTO.SchemaListElement oldListElement in oldList)
                        {
                            DataAccess.Entity.RemoveEntityFromEntityGroup(schemaGroup.ID, oldListElement.ID, txn, conn);
                        }
                    }
                    /// Add all items from the new list
                    if (schemaGroup.Schemas != null)
                    {
                        foreach (DTO.SchemaListElement newListElement in schemaGroup.Schemas)
                        {
                            DataAccess.Entity.AssignEntityToEntityGroup(schemaGroup.ID, newListElement.ID, txn, conn);
                        }
                    }

                    if (txn != null) txn.Commit(); //Commit transaction
                }
                catch (Exception)
                {
                    if (txn != null) txn.Rollback(); //Rollback transaction
                    throw;
                }
            } //Connection is disposed here

            return schemaGroup;
        }

        public static DTO.SchemaGroup GetSchemaGroup(Guid ID, SqlTransaction txn, SqlConnection conn)
        {
            DTO.SchemaGroup schemaGroup = new DTO.SchemaGroup();
            DTO.EntityGroup entityGroup = new DTO.EntityGroup();

            entityGroup = DataAccess.Entity.GetEntityGroup(ID, txn, conn);

            schemaGroup.ID = entityGroup.ID;
            schemaGroup.Name = entityGroup.Name;
            schemaGroup.Description = entityGroup.Description;

            schemaGroup.Schemas = ListSchemasByGroup(ID, txn, conn);

            return schemaGroup;
        }

        #endregion

    }
}
